//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "ProcessCathFASTAProfile.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <stdexcept>
#include <iostream>
#include <fstream>

#include <zlib.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 500000
#define LENGTHLINE 100000
#define PSIPREDBIN "/usr/local/psipred/runpsipred"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
struct LengthFreq {

  long length;
  long frequency;

  LengthFreq () {

    this->length    = 0;
    this->frequency = 0;

  }

  LengthFreq (long length, long frequency) {

    this->length    = length;
    this->frequency = frequency;

  }

};

typedef struct LengthFreq LengthFreq;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace FASTAProfileSpace {
  
  bool EqualDomain (TNode <CathFASTAProfile>* cathFASTAProfile, void* ref) {

    return (!strcmp(cathFASTAProfile->Info()->Domain()->Out(), ((CathFASTAProfile*)ref)->Domain()->Out()))?true:false;

  }
  
  bool EqualSequence (TNode <CathFASTAProfile>* cathFASTAProfile, void* ref) {

    return (!strcmp(cathFASTAProfile->Info()->Sequence()->Out(), ((CathFASTAProfile*)ref)->Sequence()->Out()))?true:false;

  }
  
  bool AlphSequence (CathFASTAProfile* cathFASTAProfile, void* ref) {

    return (strcmp(cathFASTAProfile->Sequence()->Out(), ((CathFASTAProfile*)ref)->Sequence()->Out()) < 0)?true:false;

  }
  
  bool AscDomain (CathFASTAProfile* cathFASTAProfile, void* ref) {

    return (strcmp(cathFASTAProfile->Domain()->Out(), ((CathFASTAProfile*)ref)->Domain()->Out()) < 0)?true:false;

  }
  
  bool AscCathCode (CathFASTAProfile* cathFASTAProfile, void* ref) {

    return (strcmp(cathFASTAProfile->CathCode()->Out(), ((CathFASTAProfile*)ref)->CathCode()->Out()) < 0)?true:false;

  }
  
  bool EqualLength (TNode <LengthFreq>* lengthFreq, void* ref) {

    return (lengthFreq->Info()->length == *((long*)ref))?true:false;

  }
  
  bool AscendentFreqLength(LengthFreq* lengthFreq, void* ref) {

    return (lengthFreq->length < ((LengthFreq*)ref)->length)?true:false;

  }
  
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathFASTAProfile::ProcessCathFASTAProfile() {
  
  this->namefileIn            = new String ();
  this->namefileOut           = new String ();

  this->filters               = new TListE <String> ();

  this->listCathDomainProfile = new TListE <CathFASTAProfile> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathFASTAProfile::ProcessCathFASTAProfile(const ProcessCathFASTAProfile& processCathFASTAProfile) {
  
  this->namefileIn            = new String (processCathFASTAProfile.namefileIn);
  this->namefileOut           = new String (processCathFASTAProfile.namefileOut);

  this->filters               = new TListE <String> (processCathFASTAProfile.filters);

  this->listCathDomainProfile = new TListE <CathFASTAProfile> (processCathFASTAProfile.listCathDomainProfile);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathFASTAProfile::ProcessCathFASTAProfile(const ProcessCathFASTAProfile* processCathFASTAProfile) {
  
  this->namefileIn            = new String (processCathFASTAProfile->namefileIn);
  this->namefileOut           = new String (processCathFASTAProfile->namefileOut);

  this->filters               = new TListE <String> (processCathFASTAProfile->filters);

  this->listCathDomainProfile = new TListE <CathFASTAProfile> (processCathFASTAProfile->listCathDomainProfile);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathFASTAProfile::~ProcessCathFASTAProfile() {
  
  if (this->namefileIn)             delete this->namefileIn;
  if (this->namefileOut)            delete this->namefileOut;

  if (this->filters)                delete this->filters;

  if (this->listCathDomainProfile)  delete this->listCathDomainProfile;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathFASTAProfile::NamefileIn (String* namefileIn) {
  
  if (namefileIn) this->namefileIn->In(namefileIn);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathFASTAProfile::NamefileOut (String* namefileOut) {
  
  if (namefileOut) this->namefileOut->In(namefileOut);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathFASTAProfile::Filters (TListE <String>* filters) {
  
  if (filters) *(this->filters) = *(filters);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void ProcessCathFASTAProfile::ListCathDomainProfile (TListE <CathFASTAProfile>* listCathDomainProfile) {
  
  if (listCathDomainProfile) *(this->listCathDomainProfile) = *(listCathDomainProfile);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathFASTAProfile::NamefileIn (void) {
  
  return this->namefileIn;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* ProcessCathFASTAProfile::NamefileOut (void) {
  
  return this->namefileOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* ProcessCathFASTAProfile::Filters (void) {
  
  return this->filters;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <CathFASTAProfile>* ProcessCathFASTAProfile::ListCathDomainProfile (void) {
  
  return this->listCathDomainProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::AddFilter (String* filter) {
  
  if (!filter) return false;
  
  this->filters->Add(filter);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::AddFilter (char* filter) {
  
  if (!filter) return false;
  
  this->filters->Add(new String (filter));
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::CleanFilters (void) {
  
  if (!this->filters) return false;
  
  this->filters->Clear();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::ExecuteFilters (void) {
  
  if (!this->filters) return false;
  
  this->listCathDomainProfile->VisibleAll();

  //Pre-Filters
  this->filters->SetInitial();
  
  while (this->filters->SetNext()) {
    
    if (!strcmp(this->filters->GetCurrent()->Out(), "NOT-DUPLICATED-SEQ")) {
      
      this->listCathDomainProfile->QuickSortListByArray(FASTAProfileSpace::AlphSequence, NULL);
      
      long count = 0;
      
      this->listCathDomainProfile->SetInitial();
      this->listCathDomainProfile->SetNext();
      
      while (this->listCathDomainProfile->SetNext()) {
        
        CathFASTAProfile*  currentDomainProfile = this->listCathDomainProfile->GetCurrent();
        CathFASTAProfile* previousDomainProfile = this->listCathDomainProfile->GetCurrentNode()->Previous()->Info();
        
        if (!strcmp(currentDomainProfile->Sequence()->Out(), previousDomainProfile->Sequence()->Out())) 
          this->listCathDomainProfile->GetCurrentNode()->SetHidden();
        
      }
      
    }
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::LoadData (void) {
  
  if (!this->namefileIn || !this->namefileIn->Length()) return false;
  
  bool isGZFile = (this->namefileIn->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHLINE + 1];
  String* data = new String ();
  
  if (isGZFile) zipFile = gzopen (this->namefileIn->Out(), "rb9");
  else          file.open (this->namefileIn->Out(), fstream::in);
  
  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, LENGTHLINE);
    else          file.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    data->Add(buffer);
    data->Add("\n");
    
    if (buffer[0] == '!') {
      
      CathFASTAProfile* newCathFASTAProfile = new CathFASTAProfile ();
      
      if (newCathFASTAProfile->ReadFromString(data)) 
        this->listCathDomainProfile->Add(newCathFASTAProfile);
      else 
        delete newCathFASTAProfile;
      
      data->In("");
      
    }
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  if (data)     delete data;
   
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::SplitInFile (int numberParts) {
  
  if (numberParts <= 0 || !this->listCathDomainProfile || !this->listCathDomainProfile->Length()) 
    return false;
  
  int     count    = 0, numberElem = 0;
  bool    isGZFile = (this->namefileIn->Contain("gz"))?1:0;

  char    buffer [LENGTHLINE + 1];
  
  fstream file;
  gzFile  zipFile;
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (!numberElem) {
      
      sprintf(buffer, "%s.%d\0", this->namefileIn->Out(), count++);
      
      if (isGZFile) zipFile = gzopen (buffer, "wb9");
      else          file.open (buffer, fstream::out);
      
    }
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    if (isGZFile) gzprintf(zipFile, "%s\n", currentDomainProfile->ToString()->Out()); 
    else          file << currentDomainProfile->ToString()->Out() << endl;
    
    numberElem++;
    
    if (numberElem == ((int)(this->listCathDomainProfile->Length()/numberParts))) {
      
      numberElem = 0;
      
      if (isGZFile) gzclose(zipFile);
      else          file.close();
      
    }
    
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
    
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::PredictSecondaryStructure (void) {
  
  if (!this->listCathDomainProfile || !this->listCathDomainProfile->Length()) return false;
  
  PsiPredProt* psiPredProt = new PsiPredProt ();
  String*      psiPredPath = new String (PSIPREDBIN);
  
  psiPredProt->PathPsiPredBIN(psiPredPath);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    psiPredProt->Sequence(currentDomainProfile->Sequence());
    
    if (psiPredProt->PredictSecondaryStructure()) {
      
      currentDomainProfile->SecondaryStructureP(psiPredProt->SecondStructPred());
      currentDomainProfile->SecondaryStructureC(psiPredProt->ConfidencePred());
      
      cout << "Domain: " << currentDomainProfile->Domain()->Out() << endl;
      cout << currentDomainProfile->Sequence()->Out()             << endl;
      cout << currentDomainProfile->SecondaryStructureP()->Out()  << endl;
      cout << currentDomainProfile->SecondaryStructureC()->Out()  << endl;
    
    }
    
  }
    
  if (psiPredProt) delete psiPredProt;
  if (psiPredPath) delete psiPredPath;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::UpdatePredictSecondaryStructure (void) {
  
  if (!this->listCathDomainProfile || !this->listCathDomainProfile->Length()) return false;
  
  PsiPredProt* psiPredProt = new PsiPredProt ();
  String*      psiPredPath = new String (PSIPREDBIN);
  
  psiPredProt->PathPsiPredBIN(psiPredPath);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    psiPredProt->Sequence(currentDomainProfile->Sequence());
    
    if (psiPredProt->PredictSecondaryStructure()) {
      
      currentDomainProfile->SecondaryStructureP(psiPredProt->SecondStructPred());
      currentDomainProfile->SecondaryStructureC(psiPredProt->ConfidencePred());
      
      cout << "Domain: " << currentDomainProfile->Domain()->Out() << endl;
      cout << currentDomainProfile->Sequence()->Out()             << endl;
      cout << currentDomainProfile->SecondaryStructureP()->Out()  << endl;
      cout << currentDomainProfile->SecondaryStructureC()->Out()  << endl;
    
      bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;

      fstream file;
      gzFile  zipFile;

      if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "ab9");
      else          file.open (this->namefileOut->Out(), fstream::out | fstream::app);
      
      if (isGZFile) gzprintf(zipFile, "%s\n", currentDomainProfile->ToString()->Out()); 
      else          file << currentDomainProfile->ToString()->Out() << endl;
      
      if (isGZFile) gzclose(zipFile);
      else          file.close();
      
    }
    
  }
    
  if (psiPredProt) delete psiPredProt;
  if (psiPredPath) delete psiPredPath;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::UpdatePredictSecondaryStructure (String* psiPredPath) {
  
  if (!this->listCathDomainProfile || !this->listCathDomainProfile->Length()) return false;
  
  PsiPredProt* psiPredProt = new PsiPredProt ();
  
  psiPredProt->PathPsiPredBIN(psiPredPath);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    psiPredProt->Sequence(currentDomainProfile->Sequence());
    
    if (psiPredProt->PredictSecondaryStructure()) {
      
      currentDomainProfile->SecondaryStructureP(psiPredProt->SecondStructPred());
      currentDomainProfile->SecondaryStructureC(psiPredProt->ConfidencePred());
      
      cout << "Domain: " << currentDomainProfile->Domain()->Out() << endl;
      cout << currentDomainProfile->Sequence()->Out()             << endl;
      cout << currentDomainProfile->SecondaryStructureP()->Out()  << endl;
      cout << currentDomainProfile->SecondaryStructureC()->Out()  << endl;
    
      bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;

      fstream file;
      gzFile  zipFile;

      if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "ab9");
      else          file.open (this->namefileOut->Out(), fstream::out | fstream::app);
      
      if (isGZFile) gzprintf(zipFile, "%s\n", currentDomainProfile->ToString()->Out()); 
      else          file << currentDomainProfile->ToString()->Out() << endl;
      
      if (isGZFile) gzclose(zipFile);
      else          file.close();
      
    }
    
  }
    
  if (psiPredProt) delete psiPredProt;
  if (psiPredPath) delete psiPredPath;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::HiddenContainingData (TListE<CathFASTAProfile>* listCathDomainProfile) {
  
  if (!this->listCathDomainProfile || !this->listCathDomainProfile->Length() || 
      !listCathDomainProfile       || !listCathDomainProfile->Length()) 
    return false;
  
  this->listCathDomainProfile->VisibleAll();
  
  listCathDomainProfile->SetInitial();
  
  while (listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentCathFASTAProfile = listCathDomainProfile->GetCurrent();
    long              findPosCathFASTAProfile = this->listCathDomainProfile->FirstOcurrencePosition(FASTAProfileSpace::EqualDomain, currentCathFASTAProfile);
    
    if (findPosCathFASTAProfile != -1)
      this->listCathDomainProfile->GetNode(findPosCathFASTAProfile)->SetHidden();
    
  }
  
  return true;
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::ExpandDuplicatedDataSecondaryStructure (String* namefileSS) {
 
  if (!namefileSS || !namefileSS->Length()) return false;
  
  bool                        isGZFile                = (namefileSS->Contain("gz"))?1:0;
  
  fstream                     file;
  gzFile                      zipFile;
  
  char                        buffer [LENGTHLINE + 1];
  String*                     data                    = new String ("");
  
  TListE <CathFASTAProfile>*  listCathDomainProfileSS = new TListE <CathFASTAProfile> ();
  
  if (isGZFile) zipFile = gzopen (namefileSS->Out(), "rb9");
  else          file.open (namefileSS->Out(), fstream::in);
  
  while (!((isGZFile)?gzeof(zipFile):file.eof())) {
    
    if (isGZFile) gzgets(zipFile, buffer, LENGTHLINE);
    else          file.getline(buffer, LENGTHLINE);
    
    if (!strlen(buffer)) continue;
    
    data->Add(buffer);
    data->Add("\n");
    
    if (buffer[0] == '!') {
      
      CathFASTAProfile* newCathFASTAProfile = new CathFASTAProfile ();

      if (newCathFASTAProfile->ReadFromString(data)) 
        listCathDomainProfileSS->Add(newCathFASTAProfile);
      else 
        delete newCathFASTAProfile;
      
      data->In("");
      
    }
    
  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  if (data)     delete data;
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentCathFASTAProfile = this->listCathDomainProfile->GetCurrent();
    CathFASTAProfile* findCathFASTAProfile    = listCathDomainProfileSS->FirstOcurrence(FASTAProfileSpace::EqualSequence, currentCathFASTAProfile);
    
    cout << "Find for :" << currentCathFASTAProfile->Domain()->Out();
    
    if (findCathFASTAProfile) {
      
      cout << " (OK)";
      
      currentCathFASTAProfile->SecondaryStructureP(findCathFASTAProfile->SecondaryStructureP());
      currentCathFASTAProfile->SecondaryStructureC(findCathFASTAProfile->SecondaryStructureC());
      currentCathFASTAProfile->ResiduesClassChemical(findCathFASTAProfile->ResiduesClassChemical());
      currentCathFASTAProfile->ResiduesClassPhysical(findCathFASTAProfile->ResiduesClassPhysical());
      
    }
    
    cout << "\r";
    
  }
  
  if (listCathDomainProfileSS) delete listCathDomainProfileSS;
  
  this->listCathDomainProfile->QuickSortListByArray(FASTAProfileSpace::AscCathCode, NULL);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::FillResiduesClassification (void) {
  
  if (!this->listCathDomainProfile || !this->listCathDomainProfile->Length()) return false;
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentCathFASTAProfile = this->listCathDomainProfile->GetCurrent();
    
    this->ComputeChemicalClassification(currentCathFASTAProfile);
    this->ComputePhysicalClassification(currentCathFASTAProfile);
    
  }
  
  this->listCathDomainProfile->QuickSortListByArray(FASTAProfileSpace::AscCathCode, NULL);
  
  return false;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFilterFile (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    if (isGZFile) gzprintf(zipFile, "%s\n", currentDomainProfile->ToString()->Out()); 
    else          file << currentDomainProfile->ToString()->Out() << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileSequence (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->Sequence()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileSecondaryStruture (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->SecondaryStructureP()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileConfidenceSeqStr (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->SecondaryStructureC()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileChemicalClassification (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->ResiduesClassChemical()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFilePhysicalClassification (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->ResiduesClassPhysical()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileMetaStructure (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  currentDomainProfile->ResiduesMT()->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileEncodeCHAndMTData (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();

    // Residues Chemical Classification
    // Groups
    // A) Aliphatic R-Group                  -> A, V, L, I (J -> L)
    // B) Non-Aromatic with Hidroxyl R-Group -> S, T
    // C) Sulfur containing R-Group          -> C, M
    // D) Acid and Amides                    -> D, N, E, Q (B -> D, N) (Z -> E, Q)
    // E) Basic Amino Acid                   -> R, K
    // F) Aromatic Ring                      -> F, Y, W, H
    // G) Imino Acid                         -> P
    // H) Small aliphatic R-Group            -> G
    
    //  ) X residue letter
    
    //Meta-Structure 
    //
    //      UV | W | XY 
    //      PQ | R | ST
    //      -----------
    //      KL | M | NO
    //      -----------
    //      FG | H | IJ
    //      AB | C | DE     
    //      
    //      (A,B,F,G) -> A; 
    //      (C,H)     -> B; 
    //      (D,E,I,J) -> C; 
    //      (K,L)     -> D
    //      (M)       -> E
    //      (N,O)     -> F
    //      (P,Q,U,V) -> G
    //      (R,W)     -> H
    //      (S,T,X,Y) -> I
    
//10//a,b,c,d,e,f,g,h,i,j
    //1,2,3,4,5,6,7,8,9,0
//20//k,l,m,n,o,p,q,r,s,t
    //1,2,3,4,5,6,7,8,9,0
//30//u,v,w,y,z,A,B,C,D,E
    //1,2,3,4,5,6,7,8,9,0
//40//F,G,H,I,J,K,L,M,N,O
    //1,2,3,4,5,6,7,8,9,0
//50//P,Q,R,S,T,U,V,W,Y,Z
    //1,2,3,4,5,6,7,8,9,0
//60//0,1,2,3,4,5,6,7,8,9
    //1,2,3,4,5,6,7,8,9,0
//70//,,;,.,:,{,_,(,),+,*
    //1,2,3,4,5,6,7,8,9,0
//80//%,/,-
    //1,2,3
    
    //0000000000111111111122222222223333333333444444444455555555556666666666777 
    //0123456789012345678901234567890123456789012345678901234567890123456789012
    //abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789,;.:{_()+*%/-
    
    char    encode [] = { "abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789,;.:{_()+*%/-" };
    String* code = new String ();
    
    for (int i = 0; i < currentDomainProfile->Sequence()->Length(); i++) {
      
      switch (currentDomainProfile->ResiduesClassChemical()->Out()[i]) {
        
        case 'A' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[0]); break;
            case 'C' : case 'H' :                       code->Add(encode[1]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[2]); break;
            case 'K' : case 'L' :                       code->Add(encode[3]); break;
            case 'M' :                                  code->Add(encode[4]); break;
            case 'N' : case 'O' :                       code->Add(encode[5]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[6]); break;
            case 'R' : case 'W' :                       code->Add(encode[7]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[8]); break;
          }
          break; 
        };
        case 'B' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[9]); break;
            case 'C' : case 'H' :                       code->Add(encode[10]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[11]); break;
            case 'K' : case 'L' :                       code->Add(encode[12]); break;
            case 'M' :                                  code->Add(encode[13]); break;
            case 'N' : case 'O' :                       code->Add(encode[14]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[15]); break;
            case 'R' : case 'W' :                       code->Add(encode[16]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[17]); break;
          }
          break; 
        };
        case 'C' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[18]); break;
            case 'C' : case 'H' :                       code->Add(encode[19]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[20]); break;
            case 'K' : case 'L' :                       code->Add(encode[21]); break;
            case 'M' :                                  code->Add(encode[22]); break;
            case 'N' : case 'O' :                       code->Add(encode[23]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[24]); break;
            case 'R' : case 'W' :                       code->Add(encode[25]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[26]); break;
          }
          break; 
        };
        case 'D' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[27]); break;
            case 'C' : case 'H' :                       code->Add(encode[28]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[29]); break;
            case 'K' : case 'L' :                       code->Add(encode[30]); break;
            case 'M' :                                  code->Add(encode[31]); break;
            case 'N' : case 'O' :                       code->Add(encode[32]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[33]); break;
            case 'R' : case 'W' :                       code->Add(encode[34]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[35]); break;
          }
          break; 
        };
        case 'E' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[36]); break;
            case 'C' : case 'H' :                       code->Add(encode[37]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[38]); break;
            case 'K' : case 'L' :                       code->Add(encode[39]); break;
            case 'M' :                                  code->Add(encode[40]); break;
            case 'N' : case 'O' :                       code->Add(encode[41]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[42]); break;
            case 'R' : case 'W' :                       code->Add(encode[43]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[44]); break;
          }
          break; 
        };
        case 'F' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[45]); break;
            case 'C' : case 'H' :                       code->Add(encode[46]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[47]); break;
            case 'K' : case 'L' :                       code->Add(encode[48]); break;
            case 'M' :                                  code->Add(encode[49]); break;
            case 'N' : case 'O' :                       code->Add(encode[50]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[51]); break;
            case 'R' : case 'W' :                       code->Add(encode[52]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[53]); break;
          }
          break; 
        };
        case 'G' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[54]); break;
            case 'C' : case 'H' :                       code->Add(encode[55]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[56]); break;
            case 'K' : case 'L' :                       code->Add(encode[57]); break;
            case 'M' :                                  code->Add(encode[58]); break;
            case 'N' : case 'O' :                       code->Add(encode[59]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[60]); break;
            case 'R' : case 'W' :                       code->Add(encode[61]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[62]); break;
          }
          break; 
        };
        case 'H' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[63]); break;
            case 'C' : case 'H' :                       code->Add(encode[64]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[65]); break;
            case 'K' : case 'L' :                       code->Add(encode[66]); break;
            case 'M' :                                  code->Add(encode[67]); break;
            case 'N' : case 'O' :                       code->Add(encode[68]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[69]); break;
            case 'R' : case 'W' :                       code->Add(encode[70]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[71]); break;
          }
          break; 
        };
        default  : code->Add("-"); break;
          
      }
      
    }
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  code->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;
    
    if (code) delete code;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutFASTAFileEncodePHAndMTData (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length()) return false;
  
  bool isGZFile = (this->namefileOut->Contain("gz"))?1:0;
  
  fstream file;
  gzFile  zipFile;
  
  char    buffer [LENGTHTEXT + 1];

  if (isGZFile) zipFile = gzopen (this->namefileOut->Out(), "wb9");
  else          file.open (this->namefileOut->Out(), fstream::out);
  
  this->listCathDomainProfile->SetInitial();
  
  while (this->listCathDomainProfile->SetNext()) {
    
    if (this->listCathDomainProfile->GetCurrentNode()->IsHidden()) continue;
    
    CathFASTAProfile* currentDomainProfile = this->listCathDomainProfile->GetCurrent();

    // Residues Physical Classification
    // Groups
    // A) Non-Polar + Hidrophobic                         -> A, V, L, I, M, F (J -> I, L)
    // B) Non-Polar + Hidrophilic                         -> Y, W
    // C) Polar + Neutral Charge + Hidrophobic            -> C
    // D) Polar + Neutral Charge + Hidrophilic            -> S, T, N, Q
    // E) Polar + Positive Charge                         -> K, R, H
    // F) Polar + Negative Charge                         -> D, E
    // G) Non-Polar + Hidrophilic (Glycine ó Proline)     -> G, P
    
    // X) B, X, or Z residue letter
    
    //Meta-Structure SS vs Compactness 
    //
    //      UV | W | XY 
    //      PQ | R | ST
    //      -----------
    //      KL | M | NO
    //      -----------
    //      FG | H | IJ
    //      AB | C | DE     
    //      
    //      (A,B,F,G) -> A; 
    //      (C,H)     -> B; 
    //      (D,E,I,J) -> C; 
    //      (K,L)     -> D
    //      (M)       -> E
    //      (N,O)     -> F
    //      (P,Q,U,V) -> G
    //      (R,W)     -> H
    //      (S,T,X,Y) -> I
    
//10//a,b,c,d,e,f,g,h,i,j
    //1,2,3,4,5,6,7,8,9,0
//20//k,l,m,n,o,p,q,r,s,t
    //1,2,3,4,5,6,7,8,9,0
//30//u,v,w,y,z,A,B,C,D,E
    //1,2,3,4,5,6,7,8,9,0
//40//F,G,H,I,J,K,L,M,N,O
    //1,2,3,4,5,6,7,8,9,0
//50//P,Q,R,S,T,U,V,W,Y,Z
    //1,2,3,4,5,6,7,8,9,0
//60//0,1,2,3,4,5,6,7,8,9
    //1,2,3,4,5,6,7,8,9,0
//70//,,;,.,-
    //1,2,3,4
    
    //0000000000111111111122222222223333333333444444444455555555556666 
    //0123456789012345678901234567890123456789012345678901234567890123
    //abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789,;.-
    
    char    encode [] = { "abcdefghijklmnopqrstuvwyzABCDEFGHIJKLMNOPQRSTUVWYZ0123456789,;.-" };
    String* code = new String ();
    
    for (int i = 0; i < currentDomainProfile->Sequence()->Length(); i++) {
      
      switch (currentDomainProfile->ResiduesClassChemical()->Out()[i]) {
        
        case 'A' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[0]); break;
            case 'C' : case 'H' :                       code->Add(encode[1]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[2]); break;
            case 'K' : case 'L' :                       code->Add(encode[3]); break;
            case 'M' :                                  code->Add(encode[4]); break;
            case 'N' : case 'O' :                       code->Add(encode[5]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[6]); break;
            case 'R' : case 'W' :                       code->Add(encode[7]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[8]); break;
          }
          break; 
        };
        case 'B' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[9]); break;
            case 'C' : case 'H' :                       code->Add(encode[10]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[11]); break;
            case 'K' : case 'L' :                       code->Add(encode[12]); break;
            case 'M' :                                  code->Add(encode[13]); break;
            case 'N' : case 'O' :                       code->Add(encode[14]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[15]); break;
            case 'R' : case 'W' :                       code->Add(encode[16]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[17]); break;
          }
          break; 
        };
        case 'C' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[18]); break;
            case 'C' : case 'H' :                       code->Add(encode[19]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[20]); break;
            case 'K' : case 'L' :                       code->Add(encode[21]); break;
            case 'M' :                                  code->Add(encode[22]); break;
            case 'N' : case 'O' :                       code->Add(encode[23]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[24]); break;
            case 'R' : case 'W' :                       code->Add(encode[25]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[26]); break;
          }
          break; 
        };
        case 'D' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[27]); break;
            case 'C' : case 'H' :                       code->Add(encode[28]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[29]); break;
            case 'K' : case 'L' :                       code->Add(encode[30]); break;
            case 'M' :                                  code->Add(encode[31]); break;
            case 'N' : case 'O' :                       code->Add(encode[32]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[33]); break;
            case 'R' : case 'W' :                       code->Add(encode[34]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[35]); break;
          }
          break; 
        };
        case 'E' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[36]); break;
            case 'C' : case 'H' :                       code->Add(encode[37]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[38]); break;
            case 'K' : case 'L' :                       code->Add(encode[39]); break;
            case 'M' :                                  code->Add(encode[40]); break;
            case 'N' : case 'O' :                       code->Add(encode[41]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[42]); break;
            case 'R' : case 'W' :                       code->Add(encode[43]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[44]); break;
          }
          break; 
        };
        case 'F' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[45]); break;
            case 'C' : case 'H' :                       code->Add(encode[46]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[47]); break;
            case 'K' : case 'L' :                       code->Add(encode[48]); break;
            case 'M' :                                  code->Add(encode[49]); break;
            case 'N' : case 'O' :                       code->Add(encode[50]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[51]); break;
            case 'R' : case 'W' :                       code->Add(encode[52]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[53]); break;
          }
          break; 
        };
        case 'G' : { 
          switch (currentDomainProfile->ResiduesMT()->Out()[i]) {
            case 'A' : case 'B' : case 'F' : case 'G' : code->Add(encode[54]); break;
            case 'C' : case 'H' :                       code->Add(encode[55]); break;
            case 'D' : case 'E' : case 'I' : case 'J' : code->Add(encode[56]); break;
            case 'K' : case 'L' :                       code->Add(encode[57]); break;
            case 'M' :                                  code->Add(encode[58]); break;
            case 'N' : case 'O' :                       code->Add(encode[59]); break;
            case 'P' : case 'Q' : case 'U' : case 'V' : code->Add(encode[60]); break;
            case 'R' : case 'W' :                       code->Add(encode[61]); break;
            case 'S' : case 'T' : case 'X' : case 'Y' : code->Add(encode[62]); break;
          }
          break; 
        };
        default  : code->Add("-"); break;
          
      }
      
    }
    
    sprintf(buffer, ">%s (%s) - %s = [%s]\n%s\0", currentDomainProfile->Domain()->Out(), 
                                                  currentDomainProfile->Format()->Out(), 
                                                  currentDomainProfile->CathCode()->Out(), 
                                                  currentDomainProfile->ToStringSegment()->Out(),
                                                  code->Out());
    
    if (isGZFile) gzprintf(zipFile, "%s\n", buffer); 
    else          file << buffer << endl;
    
    if (code) delete code;

  }
  
  if (isGZFile) gzclose(zipFile);
  else          file.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutResidueFrequency (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length())
    return false;
  
  // Residues Order
  // A, V, L, I, S, T, C, M, D, N, E, Q, R, K, F, Y, W, H, P, G
  // 1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20

  TListE <double>* percentResidues = new TListE <double> ();
  
  for (int i = 0; i < 20; i++)
    percentResidues->Add(new double (0.0));
  
  cout << "Number of Data " << this->listCathDomainProfile->Length() << endl;
  
  this->listCathDomainProfile->SetInitial();
  while (this->listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentCathFASTAProfile = this->listCathDomainProfile->GetCurrent();
    TListE <int>*     counterResidues         = new TListE <int> ();
    long              counter                 = 0;

    for (int i = 0; i < 20; i++)
      counterResidues->Add(new int (0));

    cout << currentCathFASTAProfile->Domain()->Out() << " - " << currentCathFASTAProfile->Sequence()->Out() << endl;
    
    for (int i = 0; i < currentCathFASTAProfile->Sequence()->Length(); i++) 
      switch (currentCathFASTAProfile->Sequence()->Out()[i]) {
        case 'A' : (*(counterResidues->Get(0)))++;  break;
        case 'V' : (*(counterResidues->Get(1)))++;  break;
        case 'L' : (*(counterResidues->Get(2)))++;  break;
        case 'I' : (*(counterResidues->Get(3)))++;  break;
        case 'S' : (*(counterResidues->Get(4)))++;  break;
        case 'T' : (*(counterResidues->Get(5)))++;  break;
        case 'C' : (*(counterResidues->Get(6)))++;  break;
        case 'M' : (*(counterResidues->Get(7)))++;  break;
        case 'D' : (*(counterResidues->Get(8)))++;  break;
        case 'N' : (*(counterResidues->Get(9)))++;  break;
        case 'E' : (*(counterResidues->Get(10)))++; break;
        case 'Q' : (*(counterResidues->Get(11)))++; break;
        case 'R' : (*(counterResidues->Get(12)))++; break;
        case 'K' : (*(counterResidues->Get(13)))++; break;
        case 'F' : (*(counterResidues->Get(14)))++; break;
        case 'Y' : (*(counterResidues->Get(15)))++; break;
        case 'W' : (*(counterResidues->Get(16)))++; break;
        case 'H' : (*(counterResidues->Get(17)))++; break;
        case 'P' : (*(counterResidues->Get(18)))++; break;
        case 'G' : (*(counterResidues->Get(19)))++; break;
        default  : counter++;                       break;
      }
      
    if (!(currentCathFASTAProfile->Sequence()->Length() - counter)) continue;  
      
    for (int i = 0; i < 20; i++) 
      *(percentResidues->Get(i)) += (double)(*(counterResidues->Get(i)))*(100)/(double)(currentCathFASTAProfile->Sequence()->Length() - counter);
    
    if (counterResidues) delete counterResidues;
    
  }
  
  for (int i = 0; i < 20; i++) 
    *(percentResidues->Get(i)) /= (double)(this->listCathDomainProfile->Length());
  
  fstream fileOut;
  
  fileOut.open(this->namefileOut->Out(), fstream::out);
  
  if (!fileOut.is_open()) {
    if (percentResidues) delete percentResidues;
    return false;
  }
  
  cout << "Writing data..." << endl;
  
  for (int i = 0; i < 20; i++)
    switch (i) {
      case 0  : fileOut << "A " << *(percentResidues->Get(0)) << endl;  break;
      case 1  : fileOut << "V " << *(percentResidues->Get(1)) << endl;  break;
      case 2  : fileOut << "L " << *(percentResidues->Get(2)) << endl;  break;
      case 3  : fileOut << "I " << *(percentResidues->Get(3)) << endl;  break;
      case 4  : fileOut << "S " << *(percentResidues->Get(4)) << endl;  break;
      case 5  : fileOut << "T " << *(percentResidues->Get(5)) << endl;  break;
      case 6  : fileOut << "C " << *(percentResidues->Get(6)) << endl;  break;
      case 7  : fileOut << "M " << *(percentResidues->Get(7)) << endl;  break;
      case 8  : fileOut << "D " << *(percentResidues->Get(8)) << endl;  break;
      case 9  : fileOut << "N " << *(percentResidues->Get(9)) << endl;  break;
      case 10 : fileOut << "E " << *(percentResidues->Get(10)) << endl; break;
      case 11 : fileOut << "Q " << *(percentResidues->Get(11)) << endl; break;
      case 12 : fileOut << "R " << *(percentResidues->Get(12)) << endl; break;
      case 13 : fileOut << "K " << *(percentResidues->Get(13)) << endl; break;
      case 14 : fileOut << "F " << *(percentResidues->Get(14)) << endl; break;
      case 15 : fileOut << "Y " << *(percentResidues->Get(15)) << endl; break;
      case 16 : fileOut << "W " << *(percentResidues->Get(16)) << endl; break;
      case 17 : fileOut << "H " << *(percentResidues->Get(17)) << endl; break;
      case 18 : fileOut << "P " << *(percentResidues->Get(18)) << endl; break;
      case 19 : fileOut << "G " << *(percentResidues->Get(19)) << endl; break;
      default  : break;
    }
  
  fileOut.close();
  
  if (percentResidues) delete percentResidues;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutSecondaryStructureFrequency (void) {
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutChemicalClassificationFrequency (void) {
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutPhysicalClassificationFrequency (void) {
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::OutMetaStructureFrequency (void) {
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::GetDistributionOfLength (void) {
  
  if (!this->namefileOut || !this->namefileOut->Length())
    return false;
  
  TListE <LengthFreq>* listLengthFreq = new TListE <LengthFreq> ();
  
  this->listCathDomainProfile->SetInitial();
  while (this->listCathDomainProfile->SetNext()) {
    
    CathFASTAProfile* currentCathFASTAProfile = this->listCathDomainProfile->GetCurrent();
    long*             tmpVaule                = new long;
    long              counter                 = 0;
    
    for (int i = 0; i < currentCathFASTAProfile->Sequence()->Length(); i++) 
      if (currentCathFASTAProfile->Sequence()->Out()[i] == '-')
        counter++;
    
    *tmpVaule = currentCathFASTAProfile->Sequence()->Length() - counter;
    
    LengthFreq* searchLengthFreq = listLengthFreq->FirstOcurrence(FASTAProfileSpace::EqualLength, tmpVaule);
    
    if (!searchLengthFreq) listLengthFreq->Add(new LengthFreq (*tmpVaule, 1));
    else                   searchLengthFreq->frequency++;
    
    if (tmpVaule) delete tmpVaule;
    
  }
  
  fstream fileOut;
  
  fileOut.open(this->namefileOut->Out(), fstream::out);
  
  if (!fileOut.is_open()) {
    if (listLengthFreq) delete listLengthFreq;
    return false;
  }
  
  listLengthFreq->QuickSortListByArray(FASTAProfileSpace::AscendentFreqLength, NULL);
  
  cout << "Writing data..." << endl;

  listLengthFreq->SetInitial();
  while (listLengthFreq->SetNext())
    fileOut << listLengthFreq->GetCurrent()->length << " " << listLengthFreq->GetCurrent()->frequency << " " << ((double)(listLengthFreq->GetCurrent()->frequency * 100)/(double)(this->listCathDomainProfile->Length())) << endl;
  
  fileOut.close();
  
  if (listLengthFreq) delete listLengthFreq;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::ComputeChemicalClassification (CathFASTAProfile* cathFASTAProfile) {
  
  if (!cathFASTAProfile || !cathFASTAProfile->Sequence() || !cathFASTAProfile->ResiduesClassChemical()) 
    return false;
  
  cathFASTAProfile->ResiduesClassChemical()->In("");
  
  for (int i = 0; i < cathFASTAProfile->Sequence()->Length(); i++) {
    
    // Residues Chemical Classification
    // Groups
    // A) Aliphatic R-Group                  -> A, V, L, I (J -> I, L)
    // B) Non-Aromatic with Hidroxyl R-Group -> S, T
    // C) Sulfur containing R-Group          -> C, M
    // D) Acid and Amides                    -> D, N, E, Q (B -> D, N) (Z -> E, Q)
    // E) Basic Amino Acid                   -> R, K
    // F) Aromatic Ring                      -> F, Y, W, H
    // G) Imino Acid                         -> P
    // H) Small aliphatic R-Group            -> G
    
    //  ) X residue letter
    
    switch ((cathFASTAProfile->Sequence()->Out()[i])) {
      
      //Group A
      case 'J' :
      case 'j' : 
        
      case 'A' :
      case 'a' : 
      case 'V' :
      case 'v' : 
      case 'L' :
      case 'l' : 
      case 'I' :
      case 'i' : cathFASTAProfile->ResiduesClassChemical()->Add('A'); break;
        
      //Group B
      case 'S' :
      case 's' : 
      case 'T' :
      case 't' : cathFASTAProfile->ResiduesClassChemical()->Add('B'); break;
        
      //Group C
      case 'C' :
      case 'c' : 
      case 'M' :
      case 'm' : cathFASTAProfile->ResiduesClassChemical()->Add('C'); break;
        
      //Group D
      case 'B' :
      case 'b' : 
      case 'Z' :
      case 'z' : 
        
      case 'D' :
      case 'd' : 
      case 'N' :
      case 'n' : 
      case 'E' :
      case 'e' : 
      case 'Q' :
      case 'q' : cathFASTAProfile->ResiduesClassChemical()->Add('D'); break;
        
      //Group E
      case 'R' :
      case 'r' : 
      case 'K' :
      case 'k' : cathFASTAProfile->ResiduesClassChemical()->Add('E'); break;
        
      //Group F
      case 'F' :
      case 'f' : 
      case 'Y' :
      case 'y' : 
      case 'W' :
      case 'w' : 
      case 'H' :
      case 'h' : cathFASTAProfile->ResiduesClassChemical()->Add('F'); break;
        
      //Group G
      case 'P' :
      case 'p' : cathFASTAProfile->ResiduesClassChemical()->Add('G'); break;
        
      //Group H
      case 'G' :
      case 'g' : cathFASTAProfile->ResiduesClassChemical()->Add('H'); break;

      case 'X' :
      case 'x' : cathFASTAProfile->ResiduesClassChemical()->Add('X'); break;
        
      default  : cathFASTAProfile->ResiduesClassChemical()->Add('X'); break;
      
    }
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool ProcessCathFASTAProfile::ComputePhysicalClassification (CathFASTAProfile* cathFASTAProfile) {
  
  if (!cathFASTAProfile || !cathFASTAProfile->Sequence() || !cathFASTAProfile->ResiduesClassPhysical()) 
    return false;
  
  cathFASTAProfile->ResiduesClassPhysical()->In("");
  
  for (int i = 0; i < cathFASTAProfile->Sequence()->Length(); i++) {
    
    // Residues Physical Classification
    // Groups
    // A) Non-Polar + Hydrophobic                         -> A, V, L, I, M, F (J -> I, L)
    // B) Non-Polar + Hydrophilic                         -> Y, W
    // C) Polar + Neutral Charge + Hydrophobic            -> C
    // D) Polar + Neutral Charge + Hydrophilic            -> S, T, N, Q
    // E) Polar + Positive Charge                         -> K, R, H
    // F) Polar + Negative Charge                         -> D, E
    // G) Non-Polar + Hydrophilic (Glycine ó Proline)     -> G, P
    
    // X) B, X, or Z residue letter
    
    switch (cathFASTAProfile->Sequence()->Out()[i]) {
      
      //Group A
      case 'J' :
      case 'j' : 
        
      case 'A' :
      case 'a' : 
      case 'V' :
      case 'v' : 
      case 'L' :
      case 'l' : 
      case 'I' :
      case 'i' : 
      case 'M' :
      case 'm' : 
      case 'F' :
      case 'f' : cathFASTAProfile->ResiduesClassPhysical()->Add('A'); break;
        
      //Group B
      case 'Y' :
      case 'y' : 
      case 'W' :
      case 'w' : cathFASTAProfile->ResiduesClassPhysical()->Add('B'); break;
        
      //Group C
      case 'C' :
      case 'c' : cathFASTAProfile->ResiduesClassPhysical()->Add('C'); break;
        
      //Group D
      case 'S' :
      case 's' : 
      case 'T' :
      case 't' : 
      case 'N' :
      case 'n' : 
      case 'Q' :
      case 'q' : cathFASTAProfile->ResiduesClassPhysical()->Add('D'); break;
        
      //Group E
      case 'K' :
      case 'k' : 
      case 'R' :
      case 'r' : 
      case 'H' :
      case 'h' : cathFASTAProfile->ResiduesClassPhysical()->Add('E'); break;
        
      //Group F
      case 'D' :
      case 'd' : 
      case 'E' :
      case 'e' : cathFASTAProfile->ResiduesClassPhysical()->Add('F'); break;
        
      //Group G
      case 'G' :
      case 'g' : 
      case 'P' :
      case 'p' : cathFASTAProfile->ResiduesClassPhysical()->Add('G'); break;
        
      case 'X' :
      case 'x' : cathFASTAProfile->ResiduesClassPhysical()->Add('X'); break;

      default  : cathFASTAProfile->ResiduesClassPhysical()->Add('X'); break;
      
    }
    
  }
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessCathFASTAProfile ProcessCathFASTAProfile::operator= (const ProcessCathFASTAProfile& processCathFASTAProfile) {
  
  this->namefileIn->In(processCathFASTAProfile.namefileIn);
  this->namefileOut->In(processCathFASTAProfile.namefileOut);
  *(this->filters)               = *(processCathFASTAProfile.filters);
  *(this->listCathDomainProfile) = *(processCathFASTAProfile.listCathDomainProfile);
  
  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
